package cn.zl.GB28181.transmit.cmd.impl;

import cn.zl.GB28181.SipLayer;
import cn.zl.GB28181.core.SSRCInfo;
import cn.zl.GB28181.core.SsrcTransaction;
import cn.zl.GB28181.event.core.SipSubscribeEvent;
import cn.zl.GB28181.session.VideoStreamSessionManager;
import cn.zl.GB28181.transmit.SIPSender;
import cn.zl.GB28181.transmit.cmd.ISIPCommander;
import cn.zl.GB28181.transmit.cmd.SIPRequestHeaderProvider;
import cn.zl.GB28181.utils.SipUtils;
import cn.zl.common.InviteSessionType;
import cn.yunbamboos.exception.AppException;
import cn.zl.config.ZLConfig;
import cn.zl.model.Device;
import cn.zl.model.DeviceChannel;
import gov.nist.javax.sip.message.SIPResponse;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.sip.InvalidArgumentException;
import javax.sip.ResponseEvent;
import javax.sip.SipException;
import javax.sip.message.Request;
import java.text.ParseException;
import java.util.List;

/**
 * 设备能力接口，用于定义设备的控制、查询能力
 */
@Component
public class SIPCommander implements ISIPCommander {

    private static final Logger logger = LoggerFactory.getLogger(SIPCommander.class);

    @Resource
    private ZLConfig config;
    @Resource
    private SIPSender sipSender;
    @Resource
    private SipLayer sipLayer;
    @Resource
    private SIPRequestHeaderProvider sipRequestHeaderProvider;
    @Resource
    private VideoStreamSessionManager videoStreamSessionManager;


    @Override
    public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException {
        StringBuilder catalogXml = new StringBuilder(200);
        String charset = device.getCharset();
        catalogXml.append("<?xml version=\"1.0\" encoding=\"").append(charset).append("\"?>\r\n");
        catalogXml.append("<Query>\r\n");
        catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
        catalogXml.append("<SN>").append((int) ((Math.random() * 9 + 1) * 100000)).append("</SN>\r\n");
        catalogXml.append("<DeviceID>").append(device.getDeviceId()).append("</DeviceID>\r\n");
        catalogXml.append("</Query>\r\n");

        String content = catalogXml.toString();
        Request request = sipRequestHeaderProvider.createMessageRequest(device, content, SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()));

        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);

        logger.info("sip commander deviceInfoQuery \n{}", content);
    }

    @Override
    public void catalogQuery(Device device, int sn, SipSubscribeEvent errorEvent) throws SipException, InvalidArgumentException, ParseException {
        StringBuilder catalogXml = new StringBuilder(200);
        String charset = device.getCharset();
        catalogXml.append("<?xml version=\"1.0\" encoding=\"").append(charset).append("\"?>\r\n");
        catalogXml.append("<Query>\r\n");
        catalogXml.append("  <CmdType>Catalog</CmdType>\r\n");
        catalogXml.append("  <SN>").append(sn).append("</SN>\r\n");
        catalogXml.append("  <DeviceID>").append(device.getDeviceId()).append("</DeviceID>\r\n");
        catalogXml.append("</Query>\r\n");

        String content = catalogXml.toString();
        Request request = sipRequestHeaderProvider.createMessageRequest(device, content, SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()));

        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);

        logger.info("sip commander catalogQuery \n{}", content);
    }

    @Override
    public void playStreamCmd(SSRCInfo ssrcInfo, Device device, DeviceChannel channel, SipSubscribeEvent okEvent, SipSubscribeEvent errorEvent) throws InvalidArgumentException, SipException, ParseException {
        String stream = ssrcInfo.getStream();
        if (device == null) {
            return;
        }
        String sdpIp = config.getSIPIP();
        StringBuilder content = new StringBuilder(200);
        content.append("v=0\r\n");
        content.append("o=").append(channel.getChannelId()).append(" 0 0 IN IP4 ").append(sdpIp).append("\r\n");
        content.append("s=Play\r\n");
        content.append("c=IN IP4 ").append(sdpIp).append("\r\n");
        content.append("t=0 0\r\n");

        if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
            content.append("m=video ").append(ssrcInfo.getPort()).append(" TCP/RTP/AVP 96 97 98 99\r\n");
        } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
            content.append("m=video ").append(ssrcInfo.getPort()).append(" TCP/RTP/AVP 96 97 98 99\r\n");
        } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {
            content.append("m=video ").append(ssrcInfo.getPort()).append(" RTP/AVP 96 97 98 99\r\n");
        }
        content.append("a=recvonly\r\n");
        content.append("a=rtpmap:96 PS/90000\r\n");
        content.append("a=rtpmap:98 H264/90000\r\n");
        content.append("a=rtpmap:97 MPEG4/90000\r\n");
        content.append("a=rtpmap:99 H265/90000\r\n");
        if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式
            content.append("a=setup:passive\r\n");
            content.append("a=connection:new\r\n");
        } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
            content.append("a=setup:active\r\n");
            content.append("a=connection:new\r\n");
        }

        if (!ObjectUtils.isEmpty(channel.getStreamIdentification())) {
            content.append("a=").append(channel.getStreamIdentification()).append("\r\n");
        }
        content.append("y=").append(ssrcInfo.getSsrc()).append("\r\n");//ssrc

        // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
        // content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备

        Request request = sipRequestHeaderProvider.createInviteRequest(device, channel.getChannelId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(), sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport()));
        sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
            // error回调事件
            // videoStreamSessionManager.remove(device.getDeviceId(), channel.getChannelId(), ssrcInfo.getStream());
            // mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
            errorEvent.response(e);
        }), e -> {
            // ok回调事件
            ResponseEvent responseEvent = (ResponseEvent) e.event;
            SIPResponse response = (SIPResponse) responseEvent.getResponse();
            String callId = response.getCallIdHeader().getCallId();
            videoStreamSessionManager.put(device.getDeviceId(), channel.getChannelId(), callId, stream, ssrcInfo.getSsrc(), response, InviteSessionType.PLAY);
            okEvent.response(e);
        });

        logger.info("sip commander playStreamCmd \n{}", content);
    }

    /**
     * 视频流停止, 不使用回调
     */
    @Override
    public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException {
        streamByeCmd(device, channelId, stream, callId, null);
    }

    @Override
    public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribeEvent okEvent) throws InvalidArgumentException, SipException, ParseException {
        if (device == null) {
            logger.warn("[发送BYE] device为 null");
            return;
        }
        List<SsrcTransaction> ssrcTransactionList = videoStreamSessionManager.getSsrcTransactionForAll(device.getDeviceId(), channelId, callId, stream);
        if (ssrcTransactionList == null || ssrcTransactionList.isEmpty()) {
            logger.info("[发送BYE] 未找到事务信息,设备： device: {}, channel: {}", device.getDeviceId(), channelId);
            throw AppException.c("未找到事务信息,设备： device: {}, channel: {} stream: {} callId: {} ", device.getDeviceId(), channelId, stream, callId);
        }

        for (SsrcTransaction ssrcTransaction : ssrcTransactionList) {
            logger.info("[发送BYE] 设备： device: {}, channel: {}, callId: {}", device.getDeviceId(), channelId, ssrcTransaction.getCallId());
//            mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());

//            mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());
            videoStreamSessionManager.removeByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getCallId());
            Request byteRequest = sipRequestHeaderProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo());
            sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent);
        }
    }

}
